package de.unibi.comet.tools;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

import de.unibi.comet.ac.AhoCorasickAutomaton;
import de.unibi.comet.ac.StringSetProvider;
import de.unibi.comet.fa.Alphabet;
import de.unibi.comet.fa.CDFA;
import de.unibi.comet.fa.DnaMotifParser;
import de.unibi.comet.fa.MarkovAdditiveChain;
import de.unibi.comet.fa.ProbabilisticString;
import de.unibi.comet.util.Log;

public class pssm_distribution {

	public static void usage() {
		System.out.println("usage: pssm_distribution <cg-content> <patternfile>");
		System.out.println("   <cg-content> cg-content to be used as i.i.d. model");
		System.out.println("   <patternfile> file containing one string and its probability per line");
		System.exit(1);
	}

	public static void main(String[] args) {
		if (args.length!=2) usage();

		double cgContent = Double.parseDouble(args[0]);
		if ((cgContent>=1.0) || (cgContent<=0.0)) {
			System.out.println("invalid cg content");
			System.exit(1);
		}
		
		FileInputStream patternFile = null;
		try {
			patternFile = new FileInputStream(args[1]);
		} catch (FileNotFoundException e) {
			System.out.println("File not found, sorry!");
			System.exit(1);
		}
		BufferedReader br = new BufferedReader(new InputStreamReader(patternFile));
		ArrayList<String> l = new ArrayList<String>();
		ArrayList<ProbabilisticString> l_ps = new ArrayList<ProbabilisticString>();
		try {
			while (true) {
				String line = br.readLine();
				if (line==null) break;
				String[] tokens = line.split(" ");
				l.add(tokens[0]);
				l_ps.add(new ProbabilisticString(tokens[0],Double.parseDouble(tokens[1])));
//				System.out.printf("line: %s\n",line);
			}
		} catch (IOException e) {
			System.out.println("I/O failure, sorry!");
			System.exit(1);
		}

//		for (ProbabilisticString ps : l) {
//			System.out.printf("%s (%f)\n",ps.getString(), ps.getProbability());
//		}
		
		Log.getInstance().setTimingActive(true);
		// Log.getInstance().setLogLevel(Log.Level.INSANE);
		Log.getInstance().setLogLevel(Log.Level.EVERYTHING);

		Alphabet alphabet = DnaMotifParser.getDnaAlphabet();
		double[] charDist = new double[4];
		charDist[alphabet.getIndex('a')] = (1.0-cgContent)*0.5;
		charDist[alphabet.getIndex('c')] = cgContent*0.5;
		charDist[alphabet.getIndex('g')] = cgContent*0.5;
		charDist[alphabet.getIndex('t')] = (1.0-cgContent)*0.5;

		int steps = 500;
		int maxMass = 100;
		
			
		// TODO generate complements
//		int length = l2.size();
//		for (int i=0; i<length; ++i) {
//			String s = l2.get(i);
//			StringBuffer complement = new StringBuffer();
//			for (int j=s.length()-1; j>=0; --j) {
//				char c = s.charAt(j);
//				if (c=='a') complement.append('t');
//				if (c=='c') complement.append('g');
//				if (c=='g') complement.append('c');
//				if (c=='t') complement.append('a');
//			}
//			l2.add(complement.toString());
//		}
		
//		StringBuilder sbuilder = new StringBuilder();
//		for (String s : l2) {
//			sbuilder.append(s);
//			sbuilder.append(',');
//		}
//		System.out.println(sbuilder.toString());
		
		int nodes = -1;
		double timeConstruction = -1.0;
		double timeMacEvolution = -1.0;
		
		// create CDFA
		StringSetProvider ssp = new StringSetProvider(l);
		AhoCorasickAutomaton aca = new AhoCorasickAutomaton();
		timeConstruction = Log.getInstance().getLastPeriodCpu();
		aca.build(ssp);
		CDFA cdfa = aca.createCDFA(alphabet);
		nodes = cdfa.getStateCount();
		
		// annotate output states with emission probabilities
		cdfa.setOutputProbabilities(l_ps);

		MarkovAdditiveChain mac = cdfa.createMAC(charDist);
		double[][] dist = new double[cdfa.getStateCount()][maxMass+1];
		dist[0][0]=1.0;
		mac.setDistribution(dist);	
		
		mac.step(steps);
		
//		for (int i=0; i<steps; ++i) {
//			mac.step(1);
//			StringBuffer sb = new StringBuffer();		
//			dist = mac.getDistribution();
//			sb.append(String.format("step %d:\n", i));
//			for (int state=0; state<mac.getStateCount(); ++state) {
//				sb.append(String.format("%03d: ", state));
//				for (int mass=0; mass<=maxMass; ++mass) {
//					sb.append(String.format(" %e", dist[state][mass]));
//				}
//				sb.append("\n");
//			}
//			sb.append("  S: ");
//			double[] massDist = mac.getMassDistribution();
//			for (int mass=0; mass<=maxMass; ++mass) {
//				sb.append(String.format(" %e", massDist[mass]));
//			}
//			sb.append("\n");
//			System.out.println(sb.toString());
//		}
		
		StringBuffer sb = new StringBuffer();
		double[] massDist = mac.getMassDistribution();
		timeMacEvolution = Log.getInstance().getLastPeriodCpu();
		
		sb.append(">>");
		for (int mass=0; mass<=maxMass; ++mass) {
			sb.append(String.format(" %e", massDist[mass]));
		}
		System.out.println(sb.toString());
		
		System.out.println(String.format("> %d %d %e", l_ps.size(), nodes, timeMacEvolution, timeConstruction));
	}
}
